/**
 * @file:  DefaultEntityFieldStuffer.java
 * @author: liang_xiaojian
 * @date:   2020/9/2 10:49
 * @copyright: 2020-2023 www.bosssoft.com.cn Inc. All rights reserved.
 */
package com.sd365.common.core.annotation.stuffer;

import cn.hutool.core.util.ObjectUtil;
import com.sd365.common.core.common.constant.EntityConsts;
import com.sd365.common.core.common.pojo.dto.BaseDTO;
import com.sd365.common.core.common.pojo.dto.TenantBaseDTO;
import com.sd365.common.core.common.pojo.entity.BaseEntity;
import com.sd365.common.core.common.pojo.entity.TenantBaseEntity;
import com.sd365.common.core.common.pojo.vo.BaseQuery;
import com.sd365.common.core.common.pojo.vo.TenantBaseQuery;
import com.sd365.common.core.context.BaseContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.Calendar;

/**
 * @class DefaultEntityFieldStuffer
 * @classdesc 切面类用于填充类通用属性
 * <p> 该类存在bug 被 DefaultCommonFieldStuffer 取代 <br>
 *     abel.zhan 2021-12-23 对该类做了重构增加了 DTO 和 query的注入 本次修改引入以下方法：
 *     switch2FillValue/autoFillDTOField/autoFillBaseQueryParamField/setTenantBaseValue
 * </p>
 * @author liang_xiaojian
 * @date 2020/9/2  10:50
 * @version 1.0.0
 * @see
 * @since
 */
@Slf4j
@Aspect
@Component
public class DefaultCommonFieldStuffer {
    @Autowired
    private  IdGenerator staticIdGenerator;
    @Autowired
    private IdGenerator idGenerator;

    @PostConstruct
    public void init() {
        staticIdGenerator = idGenerator;
    }

    @Pointcut("@annotation(com.sd365.common.core.annotation.stuffer.CommonFieldStuffer)")
    public void fillPointCut() {
        // just point cut
    }

    @Around("fillPointCut()")
    public Object autoFillEntityField(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("filling entity field...");
        // 1. 获取参数列表
        Object[] args = joinPoint.getArgs();
        if (args == null) {
            throw new IllegalArgumentException("参数列表为空");
        }
        // 2. 判断参数是否为 BaseEntity 子类
        Object param = args[0];
        if (!(param instanceof BaseEntity || param instanceof  BaseDTO || param instanceof  BaseQuery)) {
            throw new IllegalArgumentException("第一个参数不是 BaseEntity BaseDTO BaseQuery 的子类");
        }
        // 3. 获取方法类型
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        CommonFieldStuffer annotation = method.getAnnotation(CommonFieldStuffer.class);
        MethodTypeEnum methodTypeEnum = annotation.methodType();
        // 拦截设置参数值
        switch2FillValue(param,methodTypeEnum);
        // 继续执行剩下的操作
        return joinPoint.proceed();
    }
    /***
     * 判断参数类型从而调用相关方法
     * @param param  拦截的参数
     * @param methodTypeEnum  注解的方法操作类型
     */
    private void switch2FillValue(Object param ,MethodTypeEnum methodTypeEnum){
        if(param instanceof BaseEntity){
            autoFillEntityField((BaseEntity)param,methodTypeEnum);
            return ;
        }
        if(param instanceof BaseDTO){
            autoFillDTOField((BaseDTO)param,methodTypeEnum);
            return ;
        }
        if(param instanceof BaseQuery){
            autoFillBaseQueryParamField((BaseQuery) param);
            return ;
        }
    }
    /**
     *  自动为通用字段赋值
     *  <p> abel.zhan 2021-12-23 增加设置creator 和 modifier 方法 同时将creator 和 modifior提取到BaseEntity基类</p>
     * @param baseEntity 所有 entity 的基类
     */
    private   void autoFillEntityField(BaseEntity baseEntity,MethodTypeEnum methodTypeEnum) {
        if(!ObjectUtil.isAllNotEmpty(baseEntity,methodTypeEnum)){
            throw new IllegalArgumentException("参数列表异常，参数不能为空");
        }
        // 参数带有相关信息则不替换
        setTenantBaseValue(baseEntity);
        String userName=BaseContextHolder.getLoginUserName();
        switch (methodTypeEnum){
            case ADD :
                baseEntity.setId(staticIdGenerator.snowflakeId());
                baseEntity.setCreatedBy(BaseContextHolder.getUserId());
                baseEntity.setCreatedTime(Calendar.getInstance().getTime());
                baseEntity.setUpdatedBy(BaseContextHolder.getUserId());
                baseEntity.setUpdatedTime(Calendar.getInstance().getTime());
                baseEntity.setCreator(userName);// 将creator属性提取到 entity后增加
                // 没有设置时再用默认项填充
                if (baseEntity.getStatus() == null) {
                    baseEntity.setStatus(EntityConsts.INITIAL_STATUS);
                }
                baseEntity.setVersion(EntityConsts.INITIAL_VERSION);

                break;
            case UPDATE:
                baseEntity.setUpdatedBy(baseEntity.getCreatedBy());
                baseEntity.setUpdatedTime(baseEntity.getCreatedTime());
                baseEntity.setModifier(userName);
                break;
            case DELETE: // 根据传入条件删除
                break;
            case QUERY: // 依据传入条件查询
                break;
            default:
        }
    }

    /***
     *  如果是DTO参数则进行相应的注入
     * <p> abel.zhan 2021-12-23 增加设置creator 和 modifier 方法 同时将creator 和 modifior提取到BaseEntity基类</p>
     * @param baseDTO  方法类型
     * @param methodTypeEnum  方法类型
     */
    public  void autoFillDTOField(BaseDTO baseDTO,MethodTypeEnum methodTypeEnum) {
        if(!ObjectUtil.isAllNotEmpty(baseDTO,methodTypeEnum)){
            throw new IllegalArgumentException("参数列表异常，参数不能为空");
        }
        // 参数带有相关信息则不替换
        setTenantBaseValue(baseDTO);
        String userName=BaseContextHolder.getLoginUserName();
        switch (methodTypeEnum){
            case ADD :
                baseDTO.setId(staticIdGenerator.snowflakeId());
                baseDTO.setCreatedBy(BaseContextHolder.getUserId());
                baseDTO.setCreatedTime(Calendar.getInstance().getTime());
                baseDTO.setUpdatedBy(BaseContextHolder.getUserId());
                baseDTO.setUpdatedTime(Calendar.getInstance().getTime());
                // 没有设置时再用默认项填充
                if (baseDTO.getStatus() == null) {
                    baseDTO.setStatus(EntityConsts.INITIAL_STATUS);
                }
                baseDTO.setVersion(EntityConsts.INITIAL_VERSION);
                baseDTO.setCreator(userName);// 将creator属性提取到 entity后增加
                baseDTO.setModifier(userName);
                break;
            case UPDATE:
                baseDTO.setUpdatedBy(BaseContextHolder.getUserId());
                baseDTO.setUpdatedTime(Calendar.getInstance().getTime());
                baseDTO.setModifier(userName);
                break;
            case DELETE: // 根据传入条件删除
                break;
            default:

        }
    }
    /***
     *  如果是DTO参数则进行相应的注入
     * <p> abel.zhan 2021-12-23 增加设置creator 和 modifier 方法 同时将creator 和 modifior提取到BaseEntity基类</p>
     * @param baseQuery  方法类型
     */
    private   void autoFillBaseQueryParamField(BaseQuery baseQuery) {
        if(ObjectUtil.isNull(baseQuery)){
            throw new IllegalArgumentException("参数列表异常，参数不能为空");
        }
        setTenantBaseValue(baseQuery);
    }

    /**
     * 对查询进行赋值
     * @param baseQuery 查询对象
     */
    private  void setTenantBaseValue(BaseQuery baseQuery) {
        /**
         *  无论前端是否传递都将其覆盖
         */
        if(baseQuery instanceof TenantBaseQuery){
            TenantBaseQuery tenantBaseQuery=(TenantBaseQuery)baseQuery;
            tenantBaseQuery.setTenantId(BaseContextHolder.getTanentId());
            tenantBaseQuery.setOrgId(BaseContextHolder.getOrgId());
            tenantBaseQuery.setCompanyId(BaseContextHolder.getCompanyId());
        }
    }

    /**
     * 设置租户基本信息
     * @param baseDTO 从方法截取的包含租户信息的参数
     */
    private  void setTenantBaseValue(BaseDTO baseDTO) {
        /**
         * 有传租户等公用字段则使用无则从全局BaseContextHolder解析
         */
        if(baseDTO instanceof TenantBaseDTO){
            TenantBaseDTO tenantBaseDTO=(TenantBaseDTO)baseDTO;
            tenantBaseDTO.setTenantId(BaseContextHolder.getTanentId());
            tenantBaseDTO.setOrgId(BaseContextHolder.getOrgId());
            tenantBaseDTO.setCompanyId(BaseContextHolder.getCompanyId());
        }
    }

    /**
     * 设置租户基本信息
     * @param baseEntity 从方法截取的包含租户信息的参数
     */
    private  void setTenantBaseValue(BaseEntity baseEntity) {
        /**
         * 有传租户等公用字段则使用无则从全局BaseContextHolder解析
         */
        if(baseEntity instanceof TenantBaseEntity){
            if(baseEntity instanceof TenantBaseEntity){
                ((TenantBaseEntity)baseEntity).setTenantId(BaseContextHolder.getTanentId());
                ((TenantBaseEntity)baseEntity).setOrgId(BaseContextHolder.getOrgId());
                ((TenantBaseEntity)baseEntity).setCompanyId(BaseContextHolder.getCompanyId());
            }
        }
    }
}
